% Rewriter
:- source.
:- use_module(library(lists)).
:- style_check(all).
:- yap_flag(unknown, error).

:-use_module('abc_parser.yap').
:-use_module('marking.yap').
:-use_module('rewrite_utilities.yap').

%MeeraI am in the Rewriter working directory
test(A,P) :- spit_parse_tree(A,P).
test_output0 :- read_write('Web Link Ads/lowes.abc','Web Link Ads/Rlowes.abc').
test_output1 :- read_write('UnsafeURL.abc','RUnsafeURL.abc').
test_output2 :- read_write('SWFS/nu.abc','SWFS/Rnu.abc').
%main function. Reads from InFile, parses it into T, calls modify_AST
%puts that new AST, NewT back into bytecode as F, and writes it out to
%OutFile.
%read_write(InFile, Bytes, F, NewT, OutFile) :-
%

get_marked_instr_lists(InFile,NewMarkedList) :-
	get_AST(InFile, T),
	abc_parser:getABC(method_bodies,T,MethodBodies),
	initialize_marklist(MethodBodies,MarkedList),
	modify_AST(T, MarkedList, _NewT, NewMarkedList).

read_write(InFile, OutFile) :-
	%abc_parser:parseFile(InFile, _, Bytes, T),
	
	get_AST(InFile, T),
	%fileerrors,
	%open('methods.txt','write',Stream),
	%tell(Stream),
	
	abc_parser:getABC(method_bodies,T,MethodBodies),
	%format('UntrustedMethodBodies is ~w~n', [UMethodBodies]),
	%print_method_bodies(MethodBodies),
	%
	
	
	initialize_marklist(MethodBodies,MarkedList),
	
	modify_AST(T, MarkedList, NewT, NewMarkedList),
	
	writeln('after modify_AST'),
	
	print_marklists([]),
	abc_parser:abcFile(NewT, F, []),

	%break,
	abc_parser:write_file(OutFile, F), 
	

	print_marklists(NewMarkedList).
	%print_arraycount(NewMarkedList,0,'NewMarkedList').
	%told.

spit_parse_tree(InFile, ParseTree) :-

	open('out.txt','write',Stream),
	tell(Stream),

	abc_parser:readFile(InFile,Bytes),
	writeln(Bytes),
	abc_parser:abcFile(ParseTree,Bytes,[]),
	told.
%just get the Abstract Syntax Tree for a particular file
%ABCObject does not work for the URL per object example, so going to 
%skip using that - don't know why the cut is there.
get_AST(File, ABC) :-
	abc_parser:readFile(File, Bytes),
	abc_parser:abcFile(ABC, Bytes, []),
	abc_parser:init_classes, !.
	
%-----------------------> TOP-LEVEL REWRITER
%
silly_modify_AST(T, T).

%Given the old Abstract Syntax Tree, Old_T, makes desired changes
%to that to get a new Abstract Syntax Tree, New_T.
modify_AST(Old_T, MarkedList, New_T, NewMarkedList) :-
	Old_T =.. [abc, MinV, MajV, CP, MC, 
			Methods, MetaC, Metas,
		       	CC, Instances, Classes, 
			SC, Scripts, BC, MB],


	change_CP(CP, CPNew),	
	change_methodcount(MC, NewMC),
	change_methodinfo(Methods, CPNew, NewMethods),
	change_classcount(CC, NewCC),
	change_instanceinfo(Instances, CPNew, NewInstances),
	change_classinfo(Classes, NewClasses),
	change_methodbodycount(BC, NewBC),
	
	change_methodbodyinfo(MB, MarkedList, CPNew, MBNew, NewMarkedList),
	
	%write('printing after class info stuff ------------------>\n'),

	%print_arraycount(NewMethods, NewMC, 'NewMethods'),
	%print_arraycount(NewInstances, NewCC, 'NewInstances'),
	%print_arraycount(NewClasses, NewCC, 'NewClasses'),
	%	print_arraycount(MBNew, NewBC, 'NewMethodbodies'),

	%write('<-----------------------------------\n'),
	

	New_T =.. [abc, MinV, MajV, CPNew, NewMC, 
			NewMethods, MetaC, Metas, NewCC, 
			NewInstances, NewClasses, SC, 
			Scripts, NewBC, MBNew].

%------------------>REWRITE CONSTANT POOL 
%changes the constant pool. Has helper functions below
%for adding integers, strings and multinames and changing
%their counts appropriately.
change_CP(Old_CP, New_CP) :-
	Old_CP =.. [cpoolinfo, IntCount, Integers, UIntCount, 
			UIntegers, DoubleCount, Doubles, StringCount,
		       	Strings, NameSpaceCount, NameSpaces, NSSetCount,
		       	NSSets, MultinameCount, Multinames],

			%	write('printing before change_CP ------------------>\n'),
			%	print_arraycount(Strings, StringCount, 'OldCP_Strings'),
			%print_arraycount(NameSpaces, NameSpaceCount, 'OldCP_NameSpaces'),
			%print_arraycount(NSSets, NSSetCount, 'OldCP_NSSets'),
			%print_arraycount(Multinames, MultinameCount, 'OldMultinames'),
			%write('<-----------------------------------\n'),

	%add_integers(IntCount, Integers, NewIntCount, NewIntegers),
	add_strings(StringCount, Strings, NewStringCount, NewStrings),
	add_namespaces(NewStrings, NameSpaces, NameSpaceCount, NewNameSpaces, NewNameSpaceCount),
	add_multinames(NewStrings, MultinameCount, Multinames, NewMultinameCount, NewMultinames),
	New_CP =.. [cpoolinfo, IntCount, Integers, UIntCount, 
			UIntegers, DoubleCount, Doubles, NewStringCount, 
			NewStrings, NewNameSpaceCount, NewNameSpaces,
		       	NSSetCount, NSSets, NewMultinameCount, NewMultinames].

		
			%write('printing after change_CP ------------------>\n'),
			%print_arraycount(NewStrings, NewStringCount, 'NewCP_Strings'),
			%print_arraycount(NewNameSpaces, NewNameSpaceCount, 'NewCP_NameSpaces'),
			%print_arraycount(NSSets, NSSetCount, 'NewCP_NSSets'),
			%print_arraycount(NewMultinames, NewMultinameCount, 'NewMultinames'),
			%write('<-----------------------------------\n').


add_integers(IntCount, Integers, NewIntCount, NewIntegers) :-
	NewIntCount is IntCount + 1,
	%write(Integers),
	append(Integers, [1], NewIntegers).
	%write(NewIntegers).


%TODO: When adding strings, need to make sure that datatypes such as "Number",
%"void" etc. are already there, or we need to add them. For other identifiers,
%such as user-given variable names, need to make sure that they are NOT
%already there in the string array - not doing that right now.
add_strings(StringCount, Strings, NewStringCount, NewStrings) :-
	%print_arraycount(Strings, StringCount, 'String'),
	atom_codes('isOkay', L1),
	length(L1, Length1),
	S1 = string_info(Length1, L1, 'isOkay'),
	atom_codes('Number', L2),
	length(L2, Length2),
	S2 = string_info(Length2, L2, 'Number'),
	atom_codes('NativeApplication', L3),
	length(L3, Length3),
	S3 = string_info(Length3, L3, 'NativeApplication'),
	atom_codes('nativeApplication', L4),
	length(L4, Length4),
	S4 = string_info(Length4, L4, 'nativeApplication'),
	atom_codes('exit', L5),
	length(L5, Length5),
	S5 = string_info(Length5, L5, 'exit'),
	atom_codes('flash.desktop', L6),
	length(L6, Length6),
	S6 = string_info(Length6, L6, 'flash.desktop'),
	atom_codes('urlObject', L7),
	length(L7, Length7),
	S7 = string_info(Length7, L7, 'urlObject'),
	atom_codes('url', L8),
	length(L8, Length8),
	S8 = string_info(Length8, L8, 'url'),
	atom_codes('checkURL', L9),
	length(L9, Length9),
	S9 = string_info(Length9, L9, 'checkURL'),
	atom_codes('adobeURL', L10),
	length(L10, Length10),
	S10 = string_info(Length10, L10, 'adobeURL'),
	atom_codes('utdURL', L11),
	length(L11, Length11),
	S11 = string_info(Length11, L11, 'utdURL'),
	atom_codes('myURL', L12),
	length(L12, Length12),
	S12 = string_info(Length12, L12, 'myURL'),
	atom_codes('value', L13),
	length(L13, Length13),
	S13 = string_info(Length13, L13, 'value'),
	atom_codes('newURL', L14),
	length(L14, Length14),
	S14 = string_info(Length14, L14, 'newURL'),
	atom_codes('String', L15),
	length(L15, Length15),
	S15 = string_info(Length15, L15, 'String'),

	NewStringCount is StringCount + 15,
	%NewStringCount is StringCount + 2,

	append(Strings, [S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15], NewStrings).
	%append(Strings, [S1, S2, S3, S4, S5, S6], NewStrings).
	%append(Strings, [S1, S2], NewStrings).

	%print_arraycount(NewStrings, NewStringCount, 'String').


add_namespaces(Strings, NameSpaces, NameSpaceCount, NewNameSpaces, NewNameSpaceCount) :-

	find_index_stringCP('flash.desktop', Strings, I1), 
	N1 = namespace_info('CONSTANT_PackageNamespace', I1),

	find_index_stringCP('urlObject', Strings, I2),

	%format('index for urlObject is =====================~w~n',[I2]),
	N2 = namespace_info('CONSTANT_ProtectedNamespace', I2),

	append(NameSpaces, [N1, N2], NewNameSpaces),
	NewNameSpaceCount is NameSpaceCount + 2.

%TODO: Right now hardcoding the index into the Namespace set. 
add_multinames(Strings, MultinameCount, Multinames, NewMultinameCount, NewMultinames) :-
	%print_arraycount(Multinames, MultinameCount, 'Multiname'),
	NewMultinameCount is MultinameCount + 15,
	
	find_index_stringCP('isOkay', Strings, I1),
	M1 = m_info('CONSTANT_QName', qname(1, I1)), %isOkay
	
	find_index_stringCP('Number', Strings, I2),
	M2 = m_info('CONSTANT_QName', qname(1, I2)), %Number

	find_index_stringCP('NativeApplication', Strings, I3),
	M3 = m_info('CONSTANT_QName', qname(7, I3)), %NativeApplication

	find_index_stringCP('nativeApplication', Strings, I4),
	M4 = m_info('CONSTANT_QName', qname(1, I4)), %nativeApplication

	find_index_stringCP('exit', Strings, I5),
	M5 = m_info('CONSTANT_QName', qname(1, I5)), %exit

	find_index_stringCP('flash.desktop', Strings, I6),
	M6 = m_info('CONSTANT_QName', qname(1, I6)), %flash.desktop

	find_index_stringCP('urlObject', Strings, I7),
	M7 = m_info('CONSTANT_QName', qname(1, I7)), %urlObject

	find_index_stringCP('url', Strings, I8),
	M8 = m_info('CONSTANT_QName', qname(1, I8)), %url

	find_index_stringCP('checkURL', Strings, I9),
	M9 = m_info('CONSTANT_QName', qname(1, I9)), %checkURL

	find_index_stringCP('adobeURL', Strings, I10),
	M10 = m_info('CONSTANT_QName', qname(1, I10)), %adobeURL

	find_index_stringCP('utdURL', Strings, I11),
	M11 = m_info('CONSTANT_QName', qname(1, I11)), %utdURL

	find_index_stringCP('myURL', Strings, I12),
	M12 = m_info('CONSTANT_QName', qname(1, I12)), %myURL

	find_index_stringCP('value', Strings, I13),
	M13 = m_info('CONSTANT_QName', qname(1, I13)), %value

	find_index_stringCP('newURL', Strings, I14),
	M14 = m_info('CONSTANT_QName', qname(1, I14)), %newURL

	find_index_stringCP('String', Strings, I15),
	M15 = m_info('CONSTANT_QName', qname(1, I15)), %String



	append(Multinames, [M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15], NewMultinames).

%---------------->REWRITE METHOD INFO

change_methodcount(MC, NewMC) :-
	NewMC is MC + 2.

change_methodinfo(Methods, CP, NewMethods) :-
	M1 = method_info(0,0,[],1,[],option_info(none),param_info(none)),

	find_index_multinameCP('Number', CP, Type1Index),
	find_index_multinameCP('String', CP, Type2Index),
	
	CP =.. CPList,
	nth(9, CPList, Strings),
	find_index_stringCP('urlObject', Strings, NameIndex),
	M2 = method_info(2,0,[Type1Index, Type2Index],NameIndex,
			['HAS_PARAM_NAMES'],option_info(none),[0,0]),
	append(Methods, [M1, M2], NewMethods).

%---------------->REWRITE CLASSES, INSTANCES, TRAITS


%changes the class info array. Classes is an array of class_info structures.
%Each class_info structure is a tuple - Cinit - index into the method array
%of the abcFile; it references the method that is invoked when the class is 
%first created. TC - trait_count is the number of entries in the trait array,
%which holds the traits for the class. Traits is the trait array.
%
%TODO: Right now assuming that we are not adding traits to the existing class;
%instead, we are going to add another class.
%
change_classcount(OldCount, NewCount) :-
	NewCount is OldCount + 1.

change_instanceinfo(Instances, CP, NewInstances) :-

	find_index_multinameCP('urlObject', CP, NameIndex),
	find_index_multinameCP('Object', CP, SuperNameIndex),
	Flags = ['CONSTANT_ClassProtectedNs','CONSTANT_ClassSealed'],

	%find_index_namespaceCP('UnsafeURLPerObject', CP, ProtectedNSIndex),
	find_index_namespaceCP('urlObject',CP,ProtectedNSIndex),

	format('in change_instanceinfo,PNSI = ~w~n',[ProtectedNSIndex]), 
	Intrf_count is 0,
	Interface = [],
	Iinit is 5, %TODO: make generic
	TraitCount is 2,

	find_index_multinameCP('isOkay', CP, I1),
	find_index_multinameCP('url', CP, I2),

	find_index_multinameCP('Number', CP, T1),
	find_index_multinameCP('String', CP, T2),

	Traits = [trait(I1,'Trait_Slot',[],trait_slot(0,T1,0,nil),0,[]),
		  trait(I2,'Trait_Slot',[],trait_slot(0,T2,0,nil),0,[])],
	I = instance(NameIndex, SuperNameIndex, Flags,
			  ProtectedNSIndex, Intrf_count, Interface, Iinit, 
			  TraitCount, Traits),
	append(Instances, [I], NewInstances).

change_classinfo(Classes, NewClasses) :- 
	C = class_info(4, 0, []), %TODO: make generic
	append(Classes, [C], NewClasses).

%The trait structure has five fields :- Name, Kind, Flags, Data, MC,
%Metadatas. Name is an index into the multiname array of the constant
%pool. Kind field is the kind and attributes.

%-----------------> REWRITE METHOD BODIES
change_methodbodycount(BC, NewBC) :-
	NewBC is BC + 2.

change_methodbodyinfo(MBs, MarkedList, CP, NewMBs, NewMarkedList) :-


	reverse(MBs,[R1|_ReversedItems]),
	R1 = method_body(MethodNum,_,_,_,_,_,_,_,_,_,_),

	M1Num is MethodNum + 1,
	NewC1 = [0-getlocal_0,1-pushscope,2-returnvoid],

	M1 = method_body(M1Num,1,1,3,4,3,NewC1,0,[],0,[]),

	MarkedC1 = [(0-getlocal_0,'Marked'),(1-pushscope,'Marked'),(2-returnvoid,'Marked')],
							      
	find_index_multinameCP('isOkay', CP, I1),
	find_index_multinameCP('url', CP, I2),

	M2Num is MethodNum + 2,

	instruction_size(initproperty(I1),I1Size),
	O1 is 7+I1Size,
	O2 is 1+O1,
	O3 is 1+O2,
	instruction_size(initproperty(I2),I2Size),
	O4 is O3+I2Size,

	NewC2 = [

	%	0-debugfile(22),
	%				2-debugline(60),
					0-getlocal_0,
					1-pushscope,
					%6-debug(1,41,0,60),
					%11-debug(1,42,1,60),
					2-getlocal_0,
					3-constructsuper(0),
					%19-debugline(61),
					5-getlocal_0,
					6-getlocal_1,
					7-initproperty(I1),
					%25-debugline(62),
					O1-getlocal_0,
					O2-getlocal_2,		
					O3-initproperty(I2),
					%31-debugline(63),
					O4-returnvoid],

	calculate_code_length(NewC2,0,NewCodeLength),				
	M2 = method_body(M2Num,2,3,4,5,NewCodeLength,NewC2
					,0,[],0,[]),

				MarkedC2=[
					(0-getlocal_0,'Marked'),
					(1-pushscope,'Marked'),
					(2-getlocal_0,'Marked'),
					(3-constructsuper(0),'Marked'),
					(5-getlocal_0,'Marked'),
					(6-getlocal_1,'Marked'),
					(7-initproperty(I1),'Marked'),				
					(O1-getlocal_0,'Marked'),
					(O2-getlocal_2,'Marked'),		
					(O3-initproperty(I2),'Marked'),
					%31-debugline(63),
					(O4-returnvoid,'Marked')],

				

	append(MarkedList,[MarkedC1,MarkedC2],UpdatedMarkedList),
	append(MBs, [M1, M2], TempMBs),
	add_sec_var_instructions(TempMBs, CP, UpdatedMarkedList, NewMBs, NewMarkedList).
add_sec_var_instructions(MBs, CP, MarkedList, NewMBs, NewMarkedList) :- 

	find_index_multinameCP('navigateToURL', CP, InstrIndex),
	find_index_multinameCP('nativeApplication', CP, NativeAppIndex),
	find_index_multinameCP('exit', CP, HaltIndex),
	find_index_multinameCP('isOkay',CP,SecVarIndex),

	format('SecVarIndex == ~w~n',[SecVarIndex]),
	%open('out.txt','write',Stream),
	%tell(Stream),
	
	%abc_parser:getABC(method_bodies,T,MethodBodies),
	%format('UntrustedMethodBodies is ~w~n', [UMethodBodies]),
	%print_method_bodies(MBs),
	%
	%told.
	
	insert_guards_overall(MBs, InstrIndex, HaltIndex, NativeAppIndex, MarkedList, NewMBs, NewMarkedList).
	


%----------------------------------------------------------

%Search through each method body to see if it has the security 
%relevant instruction given by the method name residing at 
%MultinameIndex. Insert guards around that instruction.
%For right now, assuming that the sec rel event is going to be a 
%method call, of the form callpropvoid(index, arg_count). 
%TODO: change insert_instr_method_body to handle other method
%calls such as callproplex(index, arg_count), or callstatic(i, a).
%
%
%TODO: Not sure if setlocal_1 and getlocal_1 are okay to use 
%here. Could there be other values stored in those registers?
%How do we know whether they're free to use?
%
%InstrINdex is the multiname CP index of the security relevant instruction.
%SecVarIndex is the multiname CP index of the security variable.
%HaltIndex is the multiname CP index of the halt method.
insert_guards_overall([MB|MBs], InstrIndex, HaltIndex, NativeAppIndex, [MarkedC|MarkedCs], 
			[NewMB|NewMBs], [NewMarkedC|NewMarkedCs]) :- 


	MB =..  [method_body, Method, MS, LC, ISD,
       		MSD, CL, C, EC, E, TC, T],
	
		%writeln('in insert guards overall, Method Num is -------------->'),
		%writeln(Method),
		%writeln('\n\n'),

	insert_instr_method_body(C, CL, InstrIndex, [											     		 				  %findproperty(SecVarIndex), 
	%getproperty(SecVarIndex), 
							% if (isOkay != 1) then halt
							%pushbyte(1),
							%	ifne(5),
							%HALT	
							%findproperty(NativeAppIndex),
							%callpropvoid(HaltIndex, 0)
							nop
							%debugfile(4)
							], NewC, 0, NewCL, 0, MarkedC, NewMarkedC),
	


						
	NewLC is LC + 1,
	NewMS is MS + 1,
	NewMB =.. [method_body, Method, NewMS, NewLC, ISD,
       		MSD, NewCL, NewC, EC, E, TC, T],


		
	insert_guards_overall(MBs, InstrIndex, HaltIndex, NativeAppIndex, MarkedCs, NewMBs, NewMarkedCs).
insert_guards_overall([], _InstrIndex, _HaltIndex, _NativeAppIndex, MarkedList, [], MarkedList).



%-----------------------------------------------
insert_instr_method_body([Offset - I|Rest], CL, MultinameIndex, InstrsToInsert,
			   	NewC, OldAddOffset, NewCL, 0,
			       	[_MarkedCodePoint|MarkedCodePoints], 
				NewMarkedCodePoints) :-

					%writeln(Offset - I),
	% Check if it's the correct instruction and args.				
	I =.. [Head1, Head2|_Tail],
	Head1 = callpropvoid,
	Head2 = MultinameIndex,
	
	% Create the new front part of Instr Array
	create_oi_array(InstrsToInsert, Offset, Front, 0, SumSize, NewInstrMarks),

	% Manipulate the offsets correctly.
	NewAddOffset is OldAddOffset + SumSize,	

	% Find out the length of the old Instr
	
	instruction_size(I, CLInstr),
	%format('in IIMB, I=~w, CLInstr=~w~n',[I,CLInstr]),
	RestCL is CL - CLInstr,

	% Recursively call
	insert_instr_method_body(Rest, RestCL, MultinameIndex, InstrsToInsert, NewRest, 
				 NewAddOffset, NewRestCL, 0, MarkedCodePoints, TempMarkedCodePoints),

	% Pass up the correct NewC
	NewOffset is Offset + SumSize + OldAddOffset,
	
	Front = [FrontO - FrontI| FrontRest],
	NewFrontO is FrontO + OldAddOffset,
	

	append([NewFrontO - FrontI|FrontRest], [NewOffset - I], NewFront),
	append(NewFront, NewRest, NewC),

	NewInstrMarks = [(FrontO - FrontI, 'Marked')|MarkedRest],

	append([(NewFrontO - FrontI,'Marked')|MarkedRest],[(NewOffset - I,'Marked')],UpdatedInstrMarks),
	% append the correct Marked lists 
	append(UpdatedInstrMarks, TempMarkedCodePoints, NewMarkedCodePoints), 

	% Pass up the correct CL
	NewCL is NewRestCL + CLInstr + SumSize.

insert_instr_method_body([Offset - I|Rest], CL, MultinameIndex, InstrsToInsert,
			   	NewC, OldAddOffset, NewCL, 1,
				[_MarkedCodePoint|MarkedCodePoints], 
				[NewMarkedCodePoint|NewMarkedCodePoints]) :-

					%writeln(Offset - I),
	I =.. [Head1, Head2|_Tail],
	Head1 = callpropvoid,
	Head2 = MultinameIndex,

	% Manipulate the offsets correctly.
	NewAddOffset is OldAddOffset,

	instruction_size(I, CLInstr),
	%	format('in IIMB, I=~w, CLInstr=~w~n',[I,CLInstr]),

	RestCL is CL - CLInstr,

	NewOffset is Offset + OldAddOffset,

	% Recursively call
	insert_instr_method_body(Rest, RestCL, MultinameIndex, InstrsToInsert, NewRest,
       			       	 NewAddOffset, NewRestCL, 0, MarkedCodePoints, 
				 NewMarkedCodePoints),
		
	append([NewOffset - I], NewRest, NewC),
	
	NewMarkedCodePoint = (NewOffset - I, 'Marked'),
	% Pass up the correct CL
	NewCL is NewRestCL + CLInstr.


insert_instr_method_body([Offset - I|Rest], CL, MultinameIndex, InstrsToInsert,
				[NewOffset - I|NewRest], OldAddOffset, NewCL, Flag,
				[MarkedCodePoint|MarkedCodePoints], 
				[NewMarkedCodePoint|NewMarkedCodePoints]) :-
		% Check if it's the correct instruction and args.
		%writeln(Offset - I),		
	I =.. [Head1, Head2|_Tail],
	Head1 = callpropvoid,
	Head2 \= MultinameIndex,

	% Manipulate the offsets correctly.
	NewOffset is Offset + OldAddOffset,
	NewAddOffset is OldAddOffset,

	% Find out the length of the Instr
	instruction_size(I, CLInstr),
	%	format('in IIMB, I=~w, CLInstr=~w~n',[I,CLInstr]),

	RestCL is CL - CLInstr,
		
	% Recursively call
	insert_instr_method_body(Rest, RestCL, MultinameIndex, InstrsToInsert, NewRest, 
	                         NewAddOffset, NewRestCL, Flag,
				 MarkedCodePoints, NewMarkedCodePoints),

	NewMarkedCodePoint = MarkedCodePoint,
	% Pass up the correct CL
	NewCL is NewRestCL + CLInstr.

insert_instr_method_body([Offset - I|Rest], CL, MultinameIndex, InstrsToInsert,
				[NewOffset - I|NewRest], OldAddOffset, NewCL, Flag,
				[MarkedCodePoint|MarkedCodePoints], 
				[NewMarkedCodePoint|NewMarkedCodePoints]) :-			
	% Check if it's the correct instruction and args.
	%
	%writeln('in help 4'),
	%writeln([Offset -I|Rest]),
	%writeln([MarkedCodePoint|MarkedCodePoints]),
	%writeln(Offset - I),		
	I =.. [Head|_Tail],

	
	Head \= callpropvoid,	
		

	
	% Manipulate the offsets correctly.
	NewOffset is Offset + OldAddOffset,
	NewAddOffset is OldAddOffset,

	

	% Find out the length of the Instr
	instruction_size(I, CLInstr),
	%format('in IIMB, I=~w, CLInstr=~w~n',[I,CLInstr]),

	RestCL is CL - CLInstr,
		
	% Recursively call
	insert_instr_method_body(Rest, RestCL, MultinameIndex, InstrsToInsert, NewRest,
       	                       	 NewAddOffset, NewRestCL, Flag,
			 	 MarkedCodePoints, NewMarkedCodePoints),
	
	NewMarkedCodePoint = MarkedCodePoint,
	% Pass up the correct CL
	%
	NewCL is NewRestCL + CLInstr.

insert_instr_method_body([], CL, _MultinameIndex, _InstrsToInsert, [], _AddOffset, CL, _,
MarkedCodePoints, MarkedCodePoints).
	%writeln('case 5').
%insert_instr_method_body(C,CL,MI,ITI,NC,OAO,NCL,Flag,MCPs,NCPs) :-
%	writeln('case 6'),
%	writeln(C),
%	writeln(CL),
%	writeln(MI),
%	writeln(ITI),
%	writeln(NC),
%	writeln(OAO),
%	writeln(NCL),
%	writeln(Flag),
%	writeln(MCPs),
%	writeln(NCPs).
%-----------------------------------------------------------
create_oi_array([Instr|InstrArray], InitOffset, [InitOffset - Instr|OIArray],
		 OldSumSize, NewSumSize,
	 	 [MarkedCodePoint|MarkedCodePoints]) :-
	instruction_size(Instr, InstrSize),
	NextOffset is InitOffset + InstrSize,
	NextSumSize is OldSumSize + InstrSize,
	MarkedCodePoint = (InitOffset - Instr, 'Marked'),
	create_oi_array(InstrArray, NextOffset, OIArray, NextSumSize, NewSumSize,
			MarkedCodePoints).
create_oi_array([], _OffsetToAdd, [], SumSize, SumSize, []).


%------------> UTILITY PREDICATES

find_index_namespaceCP(String, CP, ProtectedNSIndex) :-
	CP =.. CPList,
	nth(9, CPList, Strings),
	nth(11, CPList, NameSpaces),
	%writeln(NameSpaces),

	find_index_stringCP(String, Strings, StringIndex),
	identify_namespaces(NameSpaces,StringIndex,0,ProtectedNSIndex).

identify_namespaces([N|_Rest], StringIndex, OldIndex, NewIndex) :-
	N =.. [namespace_info, _Kind, Name],
	StringIndex = Name,
	NewIndex is OldIndex + 1.
identify_namespaces([N|Rest], StringIndex, OldIndex, NewIndex) :-
	N =.. [namespace_info, _Kind, Name],
	StringIndex \= Name,
	UpdatedOldIndex is OldIndex + 1,
	identify_namespaces(Rest, StringIndex, UpdatedOldIndex, NewIndex).
identify_namespaces([], _StringIndex, _OldIndex, -1) :-
	write('The string you are searching for in the namespaces array is not present').


%--------------------------------------
%find_index_multinameCP
%looks up that String in the constant pool, and finds out which
%MultinameIndex is associated with that String in the Multiname Array.
%
find_index_multinameCP(String, CP, MultinameIndex) :-
	CP =.. CPList,
	nth(9, CPList, Strings),
	nth(15, CPList, Multinames),
	find_index_stringCP(String, Strings, StringIndex),
	identify_multinames(Multinames, StringIndex, 0, MultinameIndex).


identify_multinames([M|Rest], StringIndex, OldIndex, NewIndex) :-
	%format('case 1, M=~w~n', [M]),
	M =.. [m_info, _Type],
	UpdatedOldIndex is OldIndex + 1,
	identify_multinames(Rest, StringIndex, UpdatedOldIndex, NewIndex).
identify_multinames([M|Rest], StringIndex, OldIndex, NewIndex) :-
	%format('case 2, M=~w~n', [M]),
	M =.. [m_info, _Type, Data],
	%write(Data),
	Data =.. [_MultinameType, _],
	UpdatedOldIndex is OldIndex + 1,
	identify_multinames(Rest, StringIndex, UpdatedOldIndex, NewIndex).
identify_multinames([M|Rest], StringIndex, OldIndex, NewIndex) :-
	%format('case 3, M=~w~n', [M]),
	M =.. [m_info, _Type, Data],
	%write(Data),
	Data =.. [MultinameType, _, _],
	MultinameType = multiname,
	UpdatedOldIndex is OldIndex + 1,
	identify_multinames(Rest, StringIndex, UpdatedOldIndex, NewIndex).
identify_multinames([M|Rest], StringIndex, OldIndex, NewIndex) :-
	%format('case 4, M=~w~n', [M]),
	M =.. [m_info, _Type, Data],
	%write(Data),
	Data =.. [MultinameType, _NS, Name],
	MultinameType = qname,
	StringIndex \= Name,
	UpdatedOldIndex is OldIndex + 1,
	identify_multinames(Rest, StringIndex, UpdatedOldIndex, NewIndex).
identify_multinames([M|_Rest], StringIndex, OldIndex, NewIndex) :-
	%format('case 5, M=~w~n', [M]),
	M =.. [m_info, _Type, Data],
	%write(Data),
	Data =.. [MultinameType, _NS, Name],
	MultinameType = qname,
	StringIndex = Name,
	NewIndex is OldIndex + 1.
identify_multinames([M|Rest],StringIndex,OldIndex,NewIndex) :-
	%writeln('case 7'),
	%format('M=~w,SI=~w,OI=~w,NI=~w',[M,StringIndex,OldIndex,NewIndex]),
	M =.. [m_info, _Type, Data],
	Data =.. [MultinameType, _Name, _ParamsLength, _Params],
	MultinameType = typename,
	UpdatedOldIndex is OldIndex + 1,
	identify_multinames(Rest, StringIndex,UpdatedOldIndex,NewIndex).
identify_multinames([], _StringIndex, _OldIndex, -1) :-
	%writeln('case 6'),
	write('The string you are searching for in the multiname index is not present').
%-----------------------------------

%Given a string, finds out its index in the string array.
find_index_stringCP(String, Strings, StringIndex) :-
	identify_string(Strings, String, 0, StringIndex).

identify_string([S|_Rest], IString, OldIndex, NewIndex) :-
	S =.. [string_info, _Size, _Chars, String],
	IString = String, 
	NewIndex is OldIndex + 1.
identify_string([S|Rest], IString, OldIndex, NewIndex) :-
	S =.. [string_info, _Size, _Chars, String],
	IString \= String,
	UpdatedOldIndex is OldIndex + 1,
	identify_string(Rest, IString, UpdatedOldIndex, NewIndex).
identify_string([], _IString, _OldIndex, -1).


%--------------------------------------



